#include <hd_led.h>
#include <hd_oled_protocol_i2c.h>
#include <hd_oled.h>
#include <delay.h>
#include <pd_adc_ch.h>
#include <pd_adc.h>
#include <pd_adc_reg.h>
#include <pd_dma.h>
#include <pd_i2c_hd.h>
#include <hd_flash.h>
#include "main.h"


#define OLED_PROTOCOL       2   // Select a protocol. SPI, 1; I2C, 2;
#define OLED_PROTOCOL_IMPL  2   // Select a implement. simulate, 1; hardware, 2;

uint8_t times = 0;
static OLED *oled;
uint16_t adcData[4] = {0};

void oled_instance();

extern void SystemClock_Config(void);

int main(void) {

    SystemClock_Config();

    NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);

    oled_instance();

    GPIO *adcGPIO[] = {GPIOBuilder.build(GPIOC, LL_GPIO_PIN_0), GPIOBuilder.build(GPIOC, LL_GPIO_PIN_1),
                       GPIOBuilder.build(GPIOC, LL_GPIO_PIN_2), GPIOBuilder.build(GPIOC, LL_GPIO_PIN_3),};
    uint32_t ranks[] = {LL_ADC_REG_RANK_1, LL_ADC_REG_RANK_2, LL_ADC_REG_RANK_3, LL_ADC_REG_RANK_4,};
    uint32_t channels[] = {LL_ADC_CHANNEL_10, LL_ADC_CHANNEL_11, LL_ADC_CHANNEL_12, LL_ADC_CHANNEL_13,};
    ADCCh *adcChannel = ADCChBuilder.build(adcGPIO, 4, ranks, 4, channels, 4);

    ADCBase *adcBase = ADCBaseBuilder.build(ADC2, adcChannel, LL_ADC_SEQ_SCAN_ENABLE);// ADC scan mode(ADC_CR1_SCAN)
    ADCRegular *adcRegular = ADCRegularBuilder.build(adcBase,
                                                     LL_ADC_REG_TRIG_SOFTWARE,         // Software Trigger
                                                     LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS,// Scan Sequencer length
                                                     LL_ADC_REG_CONV_CONTINUOUS,       // Single or Continuous(ADC_CR2_CONT)
                                                     LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
    adcRegular->init(adcRegular);

    DMA *dma = DMABuilder.build(DMA2, (uint32_t) &ADC2->DR, (uint32_t) adcData, 4, LL_DMA_CHANNEL_1, LL_DMA_STREAM_2);
    dma->Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
    dma->Mode = LL_DMA_MODE_CIRCULAR;
    dma->PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
    dma->MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
    dma->PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
    dma->MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
    dma->init(dma);

    adcRegular->start(adcRegular);

    oled->showString(oled, 0, 00, "AD0:           V");
    oled->showString(oled, 0, 16, "AD1:           V");
    oled->showString(oled, 0, 32, "AD2:           V");
    oled->showString(oled, 0, 48, "AD3:           V");

    while (1) {
        oled->printf(oled, 32, 00, "%04d", adcData[0]);
        oled->showFloatNum(oled, 88, 00, (float) (3.3 * adcData[0] / 4096), 3);

        oled->printf(oled, 32, 16, "%04d", adcData[1]);
        oled->showFloatNum(oled, 88, 16, (float) (3.3 * adcData[1] / 4096), 3);

        oled->printf(oled, 32, 32, "%04d", adcData[2]);
        oled->showFloatNum(oled, 88, 32, (float) (3.3 * adcData[2] / 4096), 3);

        oled->printf(oled, 32, 48, "%04d", adcData[3]);
        oled->showFloatNum(oled, 88, 48, (float) (3.3 * adcData[3] / 4096), 3);

        oled->refresh(oled);

        delay_ms(100);
    }
}

void oled_instance() {
#if OLED_PROTOCOL == 1
    GPIO *sckGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_5); // Clock, SPIx_SCK
    GPIO *sdaGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_7); // MOSI,  SPIx_MOSI
    GPIO *resGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_3); // Reset, General IO, the chip reset pin is better
    GPIO *dcGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_1);  // Data or Command, General IO
    GPIO *csGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_2);  // Chip Select(Slave Select), General IO
    SPIGPIO *spiGPIO = SPIGPIOBuilder.build(&csGPIO, 1, sckGPIO, sdaGPIO, NULL);

#if OLED_PROTOCOL_IMPL == 1
    SPISimulate *spiObj = SPISimulateBuilder.build(spiGPIO);
#elif OLED_PROTOCOL_IMPL == 2
    SPIHardware *spiObj = SPIHardwareBuilder.build(SPI1, spiGPIO);
#endif
    SPI *spi1 = (SPI *) spiObj;
    spi1->init(spi1);
    OLEDProtocolSPI *oledProtocolObj = OLEDProtocolSPIBuilder.build(spi1, resGPIO, dcGPIO, csGPIO);

#elif OLED_PROTOCOL == 2
    GPIO *sckGPIO = GPIOBuilder.build(GPIOB, LL_GPIO_PIN_10);  // I2Cx_SCL
    GPIO *sdaGPIO = GPIOBuilder.build(GPIOB, LL_GPIO_PIN_11);  // I2Cx_SDA
#if OLED_PROTOCOL_IMPL == 1
    I2CSimulate *i2CObj = I2CSimulateBuilder.build(sckGPIO, sdaGPIO);
#elif OLED_PROTOCOL_IMPL == 2
    I2CHardware *i2CObj = I2CHardwareBuilder.build(I2C2, sckGPIO, sdaGPIO);
#endif
    I2C *i2c = (I2C *) i2CObj;
    i2c->init(i2c);
    OLEDProtocolI2C *oledProtocolObj = OLEDProtocolI2CBuilder.build(i2c);
#endif

    StorageFlash *storageFlash = StorageFlashBuilder.build();
    OLEDFont *oledFont = OLEDFontBuilder.build((Storage *) storageFlash, ENCODING_UTF8);
    oled = OLEDBuilder.build((OLEDProtocol *) oledProtocolObj, oledFont);
    oled->init(oled);
}



